package com.cskaoyan.wordmemorize.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cskaoyan.wordmemorize.common.aspect.operate.OperateLog;
import com.cskaoyan.wordmemorize.converter.RolePermissionConverter;
import com.cskaoyan.wordmemorize.dao.entity.PermissionDO;
import com.cskaoyan.wordmemorize.dao.entity.RoleDO;
import com.cskaoyan.wordmemorize.dao.entity.RolePermissionDO;
import com.cskaoyan.wordmemorize.dao.mapper.PermissionMapper;
import com.cskaoyan.wordmemorize.dao.mapper.RoleMapper;
import com.cskaoyan.wordmemorize.dao.mapper.RolePermissionMapper;
import com.cskaoyan.wordmemorize.dto.admin.*;
import com.cskaoyan.wordmemorize.request.PageRequest;
import com.cskaoyan.wordmemorize.request.PermissionCommand;
import com.cskaoyan.wordmemorize.request.RoleCommand;
import com.cskaoyan.wordmemorize.request.RolePermissionCommand;
import com.cskaoyan.wordmemorize.service.RolePermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class RolePermissionServiceImpl implements RolePermissionService {
    @Autowired
    RoleMapper roleMapper;

    @Autowired
    RolePermissionMapper rolePermissionMapper;

    @Autowired
    PermissionMapper permissionMapper;

    @Autowired
    RolePermissionConverter rolePermissionConverter;

    /**
     * 保存权限树
     * @param command
     */
    @Override
    @OperateLog(dataType = "权限", operateType = 1, description = "保存权限树")
    public void savePermissions(PermissionCommand command) {
        // 保存权限树
        savePermissionTree(command, command.getParentPermission());
    }

    private void savePermissionTree(PermissionCommand command, String parentId) {
        // 转换并保存当前权限
        PermissionDO permissionDO = rolePermissionConverter.command2PermissionDO(command);
        permissionDO.setParentPermission(parentId.equals("-1") ? -1L : Long.parseLong(parentId));
        permissionMapper.insert(permissionDO);

        // 递归保存子权限
        if (command.getChildren() != null && !command.getChildren().isEmpty()) {
            String currentId = permissionDO.getId().toString();
            for (PermissionCommand child : command.getChildren()) {
                savePermissionTree(child, currentId);
            }
        }

    }

    /**
     * 获取权限树
     * @return
     */
    @Override
    public List<PermissionDTO> getPermissions() {
        //获取权限树
        List<PermissionDTO> permissionDTOS = permissionMapper.selectAllPermission();

        return permissionDTOS;
    }

    /**
     * 删除权限
     * @param permissionId
     * @return
     */
    @Override
    @OperateLog(dataType = "权限", operateType = 2, description = "删除权限", logReturnValue = true)
    public DeletePermissionOperateDTO deletePermission(Long permissionId) {
        // 获取要删除的权限
        PermissionDO permissionDO = permissionMapper.selectById(permissionId);
        if (permissionDO == null) {
            throw new RuntimeException("权限不存在");
        }

        // 递归删除所有子权限
        deleteChildrenPermissions(permissionId);

        // 删除当前权限
        permissionMapper.deleteById(permissionId);

        return rolePermissionConverter.toDeletePermissionOperateDTO(permissionDO);
    }

    /**
     * 删除子权限
     * @param parentId
     */
    private void deleteChildrenPermissions(Long parentId) {
        // 查询所有子权限
        List<PermissionDO> children = permissionMapper.selectList(
                new LambdaQueryWrapper<PermissionDO>()
                        .eq(PermissionDO::getParentPermission, parentId)
        );

        // 递归删除子权限
        for (PermissionDO child : children) {
            deleteChildrenPermissions(child.getId());
            permissionMapper.deleteById(child.getId());
        }
    }

    /**
     * 更新权限
     * @param command
     */
    @Override
    @OperateLog(dataType = "权限", operateType = 4, description = "更新权限")
    public void updatePermission(PermissionCommand command) {

        // 更新权限信息
        PermissionDO permissionDO = rolePermissionConverter.command2PermissionDO(command);
        permissionDO.setParentPermission(command.getParentPermission().equals("-1") ? -1L : Long.parseLong(command.getParentPermission()));

        permissionMapper.updateById(permissionDO);

        // 如果有子权限，也一并更新
        if (command.getChildren() != null && !command.getChildren().isEmpty()) {
            for (PermissionCommand child : command.getChildren()) {
                updatePermission(child);
            }
        }
    }

    /**
     * 获取角色列表
     * @param pageRequest
     * @return
     */
    @Override
    public PageDTO<RoleDTO> getRoleList(PageRequest pageRequest) {
        // 查询条件
        LambdaQueryWrapper<RoleDO> roleDOLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (pageRequest.getKeyword() != null) {
            roleDOLambdaQueryWrapper.like(RoleDO::getName, pageRequest.getKeyword());
        }
        // 判断分页参数
        if (pageRequest.getPageNum() == null || pageRequest.getCount() == null) {
            // 全查
            List<RoleDO> allRoles = roleMapper.selectList(roleDOLambdaQueryWrapper);
            return rolePermissionConverter.roleList2Page(allRoles, (long) allRoles.size());
        } else {
            // 分页查
            Page<RoleDO> pageParam = new Page<>(pageRequest.getPageNum(), pageRequest.getCount());
            Page<RoleDO> roleDOPage = roleMapper.selectPage(pageParam, roleDOLambdaQueryWrapper);
            return rolePermissionConverter.roleList2Page(roleDOPage.getRecords(), roleDOPage.getTotal());
        }
    }

    /**
     * 添加角色
     * @param command
     */

    @Override
    @OperateLog(dataType = "角色", operateType = 1, description = "新增角色")
    public void addRole(RoleCommand command) {

        RoleDO roleDO = rolePermissionConverter.command2RoleDO(command);

        roleMapper.insert(roleDO);
    }

    /**
     * 更新角色
     * @param roleCommand
     */
    @Override
    @OperateLog(dataType = "角色", operateType = 4, description = "修改角色")
    public void updateRole(RoleCommand roleCommand) {

        RoleDO roleDO = rolePermissionConverter.command2RoleDO(roleCommand);

        roleMapper.updateById(roleDO);
    }

    /**
     * 更新角色权限
     * @param command
     */
    @Override
    @OperateLog(dataType = "角色权限", operateType = 4, description = "更新角色权限")
    public void updateRolePermission(RolePermissionCommand command) {
        String roleIdStr = command.getRoleId();
        long roleId = Long.parseLong(roleIdStr);

        List<String> permissions = command.getPermissions();
        permissions.forEach(permission -> {
            RolePermissionDO rolePermissionDO = new RolePermissionDO();
            rolePermissionDO.setRoleId(roleId);
            rolePermissionDO.setPermissionId(Long.valueOf(permission));
            rolePermissionMapper.insert(rolePermissionDO);
        });
    }

    /**
     * 获取角色权限
     * @param roleId
     * @return
     */
    @Override
    public RolePermissionDTO getRolePermissionList(Long roleId) {
        List<String> assignedPermissions = new ArrayList<>();
        RolePermissionDTO rolePermissionDTO = new RolePermissionDTO();
        rolePermissionDTO.setAssignedPermissions(assignedPermissions);
        //获取角色已授权权限
        LambdaQueryWrapper<RolePermissionDO> rolePermissionDOLambdaQueryWrapper = new LambdaQueryWrapper<>();
        rolePermissionDOLambdaQueryWrapper.eq(RolePermissionDO::getRoleId, roleId);
               //.select(RolePermissionDO::getPermissionId);
        List<RolePermissionDO> rolePermissionDOS = rolePermissionMapper.selectList(rolePermissionDOLambdaQueryWrapper);
        rolePermissionDOS.forEach(rolePermissionDO -> {
            rolePermissionDTO.getAssignedPermissions().add(String.valueOf(rolePermissionDO.getPermissionId()));
        });

        //获取全部权限（权限树）
        List<PermissionDTO> permissions = this.getPermissions();
        rolePermissionDTO.setSystemPermissions(permissions);

        return rolePermissionDTO;
    }

    /**
     * 删除角色
     * @param roleId
     * @return
     */
    @Override
    @OperateLog(dataType = "角色", operateType = 2, description = "删除角色", logReturnValue = true)
    public DeleteRoleOperateDTO deleteRole(Long roleId) {

        RoleDO roleDO = roleMapper.selectById(roleId);

        DeleteRoleOperateDTO deleteRoleOperateDTO = rolePermissionConverter.toDeleteRoleOperateDTO(roleDO);

        //删除角色(role)
        roleMapper.deleteById(roleId);

        //删除角色权限(role_permission)
        LambdaUpdateWrapper<RolePermissionDO> rolePermissionDOLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        rolePermissionDOLambdaUpdateWrapper.eq(RolePermissionDO::getRoleId, roleId);
        rolePermissionMapper.delete(rolePermissionDOLambdaUpdateWrapper);

        return deleteRoleOperateDTO;
    }

    /**
     * 删除角色权限
     * @param roleId
     * @param permissionId
     * @return
     */
    @Override
    @OperateLog(dataType = "角色权限", operateType = 2, description = "删除角色权限", logReturnValue = true)
    public DeleteRolePermissionOperateDTO deleteRolePermission(Long roleId, Long permissionId) {
        //找到permissionId是否有子权限，得到子权限的permissionId
        List<Long> permissionIds = permissionMapper.selectPermissionIdsRecursive(permissionId);

        //删除权限
        permissionIds.forEach(permission -> {
            LambdaUpdateWrapper<RolePermissionDO> rolePermissionDOLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            rolePermissionDOLambdaUpdateWrapper.eq(RolePermissionDO::getRoleId, roleId)
                    .eq(RolePermissionDO::getPermissionId, permission);
            rolePermissionMapper.delete(rolePermissionDOLambdaUpdateWrapper);
        });

        //构造返回值
        RoleDO roleDO = roleMapper.selectById(roleId);
        PermissionDO permissionDO = permissionMapper.selectById(permissionId);
        DeleteRolePermissionOperateDTO deleteRolePermissionOperateDTO = new DeleteRolePermissionOperateDTO();
        deleteRolePermissionOperateDTO.setRoleId(roleId);
        deleteRolePermissionOperateDTO.setRoleName(roleDO.getName());
        deleteRolePermissionOperateDTO.setPermissionId(permissionId);
        deleteRolePermissionOperateDTO.setPermissionAlias(permissionDO.getPermissionAlias());

        return deleteRolePermissionOperateDTO;
    }

}
